package switchviz.network.netswitch;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

import switchviz.core.SwitchVizException;
import switchviz.core.data.OIDDataPair;
import switchviz.core.signal.ISignal;
import switchviz.core.signal.OIDSignal;
import switchviz.core.signal.SignalUtil;
import switchviz.network.NetworkData;
import switchviz.network.NetworkException;
import switchviz.network.snmp.SnmpAdaptor;
import switchviz.network.snmp.SnmpStatus;


public class Switch
{
	private static Logger logger = Logger.getLogger(Switch.class);
	
	private SwitchDataModel _switchDataModel = null;
	private SnmpAdaptor _snmpAdaptor = null;
	private List<ISignal> _signals = new ArrayList<ISignal>();
	
	public Switch(SwitchDataModel switchDataModel) throws NetworkException
	{
		_switchDataModel = switchDataModel;
		
		try
		{
			logger.info("Create snmp adaptor.");
			
			_snmpAdaptor = new SnmpAdaptor(_switchDataModel.getAddress(), 
					_switchDataModel.getPort(),
					_switchDataModel.getCommunity(),
					_switchDataModel.getTimeout(),
					_switchDataModel.getMaxRetries(),
					_switchDataModel.getPDUCapacity());
		}
		catch(IOException e)
		{
			throw new NetworkException("Error creating snmp adaptor.", e);
		}
	}
	
	public SnmpStatus getNetworkStatus()
	{
		return _snmpAdaptor.getSnmpStatus();
	}
	
	public SwitchDataModel getSwitchDataModel()
	{
		return _switchDataModel;
	}
	
	public int getSignalListSize()
	{
		return _signals.size();
	}
	
	public void send() throws NetworkException
	{
		send(false);
	}
	
	public void send(boolean synchron) throws NetworkException
	{
		try
		{
			logger.info("Sending packages.");
			
			_snmpAdaptor.send(synchron);
		}
		catch(IOException exception)
		{
			throw new NetworkException("Error sending pdu's.", exception);
		}
	}
	
	private void add(ISignal signal, boolean get) throws NetworkException
	{
		try
		{
			ISignal equalSignal = null;
			
			if(!signal.getClass().equals(OIDSignal.class))
				equalSignal = SignalUtil.findSignal(_signals, signal);

			if (equalSignal == null)
			{
				if (logger.isInfoEnabled())
					logger.info("Adding signal '" + signal.getAliasName() 
							+ " (port=" + signal.getPort() + ")' to snmp adaptor.");
			
				NetworkData data = new NetworkData(signal.getOid()); 
				
				if(get)
					_snmpAdaptor.addGet(data);
				else
					_snmpAdaptor.addGetNext(data);
				
				signal.setData(data);
				
				_signals.add(signal);
			}
			else
			{
				if (logger.isInfoEnabled())
					logger.info("Redirect data because signal '" + signal.getAliasName() 
							+ " (port=" + signal.getPort() + ")' already exists.");
				
				signal.setData(equalSignal.getData());
			}
		}
		catch (SwitchVizException exception)
		{
			throw new NetworkException("Error adding signal '" + signal.getAliasName() + "'.", exception);
		}
	}
	
	public void add(ISignal signal) throws NetworkException
	{
		add(signal, true);
	}
	
	public void addBulk(ISignal signal) throws NetworkException
	{
		add(signal, false);
	}
	
	public void close() throws NetworkException
	{
		try
		{
			logger.info("Closing connection.");
			
			_snmpAdaptor.close();
		}
		catch(IOException e)
		{
			throw new NetworkException("Error closing adaptor.", e);
		}
	}
	
	public String toString()
	{
		return _switchDataModel.getName() + " @ " + _switchDataModel.getAddress() + ":" + _switchDataModel.getPort();
	}
	
	private static SnmpAdaptor getSnmpAdaptor(SwitchDataModel switchDataModel) throws IllegalArgumentException, IOException
	{
		SnmpAdaptor snmpAdaptor = new SnmpAdaptor(switchDataModel.getAddress(), 
				switchDataModel.getPort(), 
				switchDataModel.getCommunity(),
				switchDataModel.getTimeout(),
				switchDataModel.getMaxRetries(),
				switchDataModel.getPDUCapacity());
		return snmpAdaptor;
	}
	
	private static Object[] requestData(SwitchDataModel switchDataModel, String[] oidarray, boolean get) throws NetworkException
	{
		try
		{
			List<NetworkData> datalist = new ArrayList<NetworkData>();
			SnmpAdaptor snmpAdaptor = getSnmpAdaptor(switchDataModel);
			
			for(String oid : oidarray)
			{
				NetworkData data = new NetworkData(oid);
				if(get)
					snmpAdaptor.addGet(data);
				else
					snmpAdaptor.addGetNext(data);
				datalist.add(data);
			}
			snmpAdaptor.send(true);
			snmpAdaptor.close();
			
			Object[] objarray = new Object[datalist.size()];
			for(int i = 0; i < objarray.length; ++i)
			{
				objarray[i] = datalist.get(i).getValue();
			}
			return objarray;
		}
		catch (Exception e)
		{
			throw new NetworkException("Error requesting data.", e);
		}
	}
	
	public static OIDDataPair[] requestBulkData(SwitchDataModel switchDataModel, String oid, int limit) throws IllegalArgumentException, IOException
	{
		SnmpAdaptor snmpAdaptor = getSnmpAdaptor(switchDataModel);
		OIDDataPair[] objarray = snmpAdaptor.getSynchronBulk(oid, limit);
		snmpAdaptor.close();
		return objarray;
	}
	
	public static Object[] requestData(SwitchDataModel switchDataModel, String[] oidarray) throws NetworkException
	{
		return requestData(switchDataModel, oidarray, true);
	}
	
	public static Object[] requestNextData(SwitchDataModel switchDataModel, String[] oidarray) throws NetworkException
	{
		return requestData(switchDataModel, oidarray, false);
	}
}
